<template>
    <div class="container" v-show="isShow" ref="floatRef" @mousemove="e => checkActionType(e)">
        <div class="dragbar" @mousedown="e => mousedown(e, true)">
            <div @click="() => hiddenDragBarHandler()" v-show="canHidden" title="隐藏" class="hidden">→</div>
            <div @click="() => hiddenDragBarHandler()" v-show="isVisible && canHidden" class="showIcon">
                <span class="iconfont icon-Chat"></span>
            </div>
            <slot name="dragbar"></slot>
        </div>
        <div class="mian-box" @mousedown="e => mousedown(e, false)">
            <slot name="main"></slot>
        </div>
    </div>
</template>

<script setup lang="ts">
import eventBus from "@/Util/EventBus";
import { ActionType, ResizeType, FloatWinPos } from "../Util/Constant";
const floatRef = ref()
const isShow = ref<boolean>(true)

defineExpose({
    isShow
})
let { dragbarHeight, defaultWidth, canHidden, defaultOffsetX, zIndex, defaultOffsetY, defaultHeight, prohibitResize, dragBarEleId, minWidth, minHeight, isInMid } = defineProps<{
    dragbarHeight: number,
    dragBarEleId: string, // 允许拖拽元素的id
    minWidth?: number,
    minHeight?: number,
    defaultOffsetX?: number,
    defaultOffsetY?: number,
    defaultWidth?: number,
    defaultHeight?: number,
    prohibitResize?: boolean, // 是否禁止改变弹框大小
    isInMid?: boolean, // 弹框是否垂直居中
    zIndex?: number,
    canHidden?: boolean
}>()

const dragbarSize = computed(() => {
    return dragbarHeight + 'px'
})
const mainbarSize = computed(() => {
    return floatHeight.value + 'px'
})

const midXPos = computed(() => {
    return winWidth.value / 2 - floatWidth.value / 2
})
const midYPos = computed(() => {
    return winHeight.value / 2 - floatHeight.value / 2
})
let divStartLeft = ref<number>(0);
let divStartTop = ref<number>(0);
let startOffsetX: number;
let startOffsetY: number;
let startPageX: number;
let startPageY: number;
let winWidth = ref<number>(0);
let winHeight = ref<number>(0);
let floatWidth = ref<number>(0);
let floatHeight = ref<number>(0);
let maxOffsetX = ref<number>(0);
let maxOffsetY = ref<number>(0);
let floatOffsetX = 0;
let floatOffsetY = 0;
let floatMinWidth = minWidth || defaultWidth || 100;
let floatMinHeight = minHeight || defaultHeight || 400;
let needResize = ref<boolean>(false)
let actionType: ActionType = ActionType.None
let resizeType: ResizeType = ResizeType.None
let position: FloatWinPos = FloatWinPos.Left
let isDragBar: boolean;
let isVisible = ref<boolean>(false)
onMounted(() => {
    let ele = floatRef.value as HTMLDivElement
    defaultWidth && (ele.style.width = defaultWidth + 'px')
    defaultHeight && (ele.style.height = defaultHeight + 'px')
    zIndex && (ele.style.zIndex = zIndex.toString())
    updateFloatAttr(ele)
    FloatWinDefultPosition(ele)
    canHidden && hiddenDragBarHandler(true)
})

window.onresize = () => {
    let newWidth = window.innerWidth
    let ele = floatRef.value as HTMLDivElement
    if (isVisible.value) {
        ele.style.transform = `translate(${newWidth}px, ${floatOffsetY}px)`
    } else if (floatOffsetX + floatWidth.value > newWidth) {
        ele.style.transform = `translate(${newWidth - floatWidth.value}px, ${floatOffsetY}px)`
    }
    updateFloatAttr(floatRef.value)
}

let updateFloatAttr = (ele: HTMLDivElement) => {
    divStartTop.value = ele.offsetTop
    divStartLeft.value = ele.offsetLeft
    winWidth.value = document.body.clientWidth
    winHeight.value = document.body.clientHeight
    floatWidth.value = ele.clientWidth
    floatHeight.value = ele.clientHeight
    maxOffsetX.value = winWidth.value - floatWidth.value
    maxOffsetY.value = winHeight.value - floatHeight.value
}
const FloatWinDefultPosition = (ele: HTMLDivElement) => {
    let x = midXPos.value * 2;
    let y = midYPos.value;
    if (isInMid) {
        x = midXPos.value
        y = midYPos.value
    } else if (defaultOffsetX && defaultOffsetY) {
        x = defaultOffsetX
        y = defaultOffsetY
    }
    floatOffsetX = x
    floatOffsetY = y
    ele.style.transform = `translate(${x}px, ${y}px)`
}
const checkActionType = (e: MouseEvent): any => {
    let offsetX = e.clientX - floatOffsetX
    let offsetY = e.clientY - floatOffsetY
    let at: ActionType = ActionType.None;
    let rt: ResizeType = ResizeType.None;
    let edgeSize = 5
    if (offsetX > floatWidth.value - edgeSize && offsetY > floatHeight.value - edgeSize && !prohibitResize) {
        setCursor('nw-resize')
        at = ActionType.Resize
        rt = ResizeType.ResizeAll
        needResize.value = true
    } else if (offsetX > floatWidth.value - edgeSize && !prohibitResize) {
        setCursor('e-resize')
        at = ActionType.Resize
        rt = ResizeType.ResizeWidth
        needResize.value = true
    } else if (offsetY > floatHeight.value - edgeSize && !prohibitResize) {
        setCursor('s-resize')
        at = ActionType.Resize
        rt = ResizeType.ResizeHeight
        needResize.value = true
    } else if (offsetY < dragbarHeight) {
        needResize.value = false
        at = ActionType.Move
        if (actionType === ActionType.None && resizeType === ResizeType.None) setCursor('grab')
    } else {
        if (actionType === ActionType.None && resizeType === ResizeType.None) setCursor('default')
        needResize.value = false
    }
    return { at, rt }
}
let setCursor = (cursor: string) => {
    let ele = floatRef.value as HTMLDivElement
    if (ele) {
        ele.style.cursor = cursor
    }
}
const mousedown = (event: MouseEvent, dragBar: boolean) => {
    isDragBar = dragBar
    startOffsetX = event.offsetX;
    startOffsetY = event.offsetY;
    startPageX = event.pageX;
    startPageY = event.pageY; // 鼠标按下确定这次操作的目的，是拖动还是放大缩小
    let { at, rt } = checkActionType(event);
    actionType = at;
    resizeType = rt;
    if (at === ActionType.Move && (!dragBar || (event.target && (event.target as HTMLElement).id !== dragBarEleId))) return;
    dragBar && setCursor('grabbing');
    document.addEventListener('mousemove', mouseMoveHandler)
    document.addEventListener('mouseup', mouseUpHandler)
}
let mouseUpHandler = () => {
    let ele = floatRef.value as HTMLDivElement;
    document.removeEventListener('mousemove', mouseMoveHandler)
    // 更新属性
    updateFloatAttr(ele)
    actionType = ActionType.None;
    resizeType = ResizeType.None;
    isDragBar && setCursor('grab')
    // if (position !== FloatWinPos.Middle) {
    //     let timer = setTimeout(() => {
    //         hiddenDragBar(position)
    //         clearTimeout(timer)
    //     }, 1000)
    // }
    document.removeEventListener('mouseup', mouseUpHandler)
}

let hiddenDragBarHandler = (noTransition?: boolean) => {
    let ele = floatRef.value as HTMLDivElement;
    !noTransition && (ele.style.transition = '.7s')
    hiddenDragBar()
    updateFloatAttr(ele)
    eventBus.emit('updateFriendList');
    let time = setTimeout(() => {
        ele.style.transition = '0s'
        clearTimeout(time)
    }, 700)
}

function hiddenDragBar() {
    let ele = floatRef.value as HTMLDivElement
    if (!isVisible.value) {//隐藏
        ele.style.transform = `translate(${winWidth.value}px, ${floatOffsetY}px)`
        floatOffsetX = winWidth.value
        let time = setTimeout(() => {
            isVisible.value = !isVisible.value
            clearTimeout(time)
        }, 700)
    } else { //弹出
        isVisible.value = !isVisible.value
        ele.style.transform = `translate(${winWidth.value - floatWidth.value}px, ${floatOffsetY}px)`
        floatOffsetX = winWidth.value - floatWidth.value
    }
}

function mouseMoveHandler(e: MouseEvent) {
    let ele = floatRef.value as HTMLDivElement
    let pageX = e.pageX
    let pageY = e.pageY
    position = FloatWinPos.Middle
    if (actionType === ActionType.Move) {
        let offsetX = pageX - divStartLeft.value - startOffsetX
        let offsetY = pageY - divStartTop.value - startOffsetY
        if (offsetX <= 0) {
            position = FloatWinPos.Left
            offsetX = 0;
        }
        if (offsetY <= 0) {
            position = FloatWinPos.Top
            offsetY = 0;
        }
        if (offsetX + floatWidth.value >= winWidth.value) {
            position = FloatWinPos.Right
            offsetX = maxOffsetX.value;
        }
        if (offsetY + floatHeight.value >= winHeight.value) {
            position = FloatWinPos.Bottom
            offsetY = maxOffsetY.value;
        }
        ele.style.transform = `translate(${offsetX}px, ${offsetY}px)`
        floatOffsetX = offsetX
        floatOffsetY = offsetY
    } else if (actionType === ActionType.Resize && !prohibitResize) {
        let width = pageX - startPageX + floatWidth.value
        let height = pageY - startPageY + floatHeight.value
        if (resizeType === ResizeType.ResizeWidth && width >= floatMinWidth) {
            ele.style.width = width + 'px'
        } else if (resizeType === ResizeType.ResizeHeight && height >= floatMinHeight) {
            ele.style.height = height + 'px'
        } else if (resizeType === ResizeType.ResizeAll) {
            width >= floatMinWidth && (ele.style.width = width + 'px')
            height >= floatMinHeight && (ele.style.height = height + 'px')
        }
    }
}
</script>


<style scoped lang="less">
.container {
    position: absolute;
    top: 0;
    left: 0;
    width: 200px;
    height: 600px;
    display: flex;
    flex-direction: column;
    background: url('/images/bg.png') no-repeat;
    border-radius: 2px;
    z-index: 99999;

    .dragbar {
        user-select: none;
        height: v-bind(dragbarSize);
        position: relative;

        .hidden {
            position: absolute;
            width: 22px;
            height: 22px;
            text-align: center;
            line-height: 22px;
            right: 5px;
            top: 0;
            color: #fff;
            cursor: pointer;
            transition: .5s;

            &:hover {
                background-color: #ccc;
            }
        }

        .showIcon {
            position: absolute;
            left: -60px;
            top: 0;
            width: 60px;
            height: 30px;
            line-height: 30px;
            border-radius: 15px 0 0 15px;
            cursor: pointer;
            background: linear-gradient(to right, #4facfe, #00f2fe);

            .iconfont {
                font-size: 25px;
                margin-left: 10px;
                background: linear-gradient(to right, #ffc486, #fd7434);
                -webkit-background-clip: text;
                color: transparent;
            }
        }
    }

    .mian-box {
        background-color: rgba(204, 210, 219, .5);
        overflow: auto;
        height: v-bind(mainbarSize);
    }
}
</style>